#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MAXSIZE 128
#define MAXARGS 32

// 命令行参数表
int gargc = 0;
char* gargv[MAXARGS];
const char* gsep = " "; 

char* genv[MAXARGS];
int genvc = 0;

// 环境变量表
char cwd[MAXSIZE];
int lastcode = 0;

// 定义重定向
#define NoneRedir 0
#define InputRedir 1
#define AppRedir 2
#define OutputRedir 3

int redir_type = NoneRedir;
char* filename = NULL;
#define TrimSpace(start) do{\
  while(isspace(*start))\
  {start++;}\
}while(0)

void LoadEnv()
{
  extern char** environ;
  for(;environ[genvc];genvc++)
  {
    genv[genvc] = new char[4096];
    strcpy(genv[genvc],environ[genvc]);
  }
  genv[genvc] = NULL;
  
 // for(int i = 0;genv[i];i++)
 // {
 //   printf("genv[%d]:%s\n",i,genv[i]);
 // }
}

static std::string rfindDir(const std::string &p)
{
  if(p == "/")
  {
    return p;
  }
  const std::string psep = "/";
  auto pos = p.rfind(psep);
  if(pos == std::string::npos)
  {
    return std::string();
  }
  return p.substr(pos+1);
}

const char* GetUserName()
{
  char* name = getenv("USER");
  if(name == NULL)
  {
    return "none";
  }
  return name;
}
const char* GetHostName()
{
  char* hostname = getenv("HOSTNAME");
  if(hostname == NULL)
  {
    return "none";
  }
  return hostname;
}
const char* GetPwd() 
{
  char* pwd = getenv("PWD");
  //char* pwd = getcwd(cwd,sizeof(cwd));

  if(pwd == NULL)
  {
    return "none";
  }
  //return cwd;
  return pwd;
}

void PrintCommandLine()
{
  printf("[%s@%s %s]# ",GetUserName(),GetHostName(),rfindDir(GetPwd()).c_str());
  fflush(stdout);
}

int GetCommand(char* commandline,int size)
{
  if(NULL == fgets(commandline,size,stdin))
  {
    perror("fgets");
    return 0;
  }
  commandline[strlen(commandline)-1] = '\0';
  return strlen(commandline);
}

void ParseRedir(char* commandline)
{
  char* start = commandline;
  char* end = commandline + strlen(commandline);
  while(start < end)
  {
    if(*start == '>')
    {
      //输出重定向 || 追加重定向
      if(*(start+1) == '>')
      {
        *start = '\0';
        start++;
        *start = '\0';
        start++;
        // 跳过文件名的前空格
        TrimSpace(start);
        filename = start;
        redir_type = AppRedir;
        break;
      }
       *start = '\0';
       start++;
       // 跳过文件名的前空格
       TrimSpace(start);
       filename = start;
       redir_type = OutputRedir;
       break;
    }
    else if(*start == '<')
    {
      //输入重定向
      *start = '\0';
      start++;
      TrimSpace(start);
      filename = start;
      redir_type = InputRedir;
      break;
    }
    else{
      //命令或文件名
      start++;
    }
  }
}




int ParseCommand(char* commandline)
{
  gargc = 0;
  memset(gargv,0,sizeof(gargv));

  gargv[0] = strtok(commandline,gsep);
  
  while(gargv[++gargc] = strtok(NULL,gsep));
  //int i = 0;
  //for(;gargv[i];i++)
  //{
  //  printf("gargv[%d]:%s\n",i,gargv[i]);
  //}
  return gargc;
}

int CheckBuiltinExecute()
{
  if(strcmp(gargv[0],"cd") == 0)
  {
    //内建命令
    if(gargc == 2)
    {
      // 新的目标路径 gargv[1]
      chdir(gargv[1]);
      char pwd[1024];
      getcwd(pwd,sizeof(pwd));
      snprintf(cwd,sizeof(cwd),"PWD=%s",pwd); 
      putenv(cwd);
      lastcode = 0;
    }
    return 1;
  }
  else if(strcmp(gargv[0],"echo") == 0)
  {
    if(gargc == 2)
    { 
      if(gargv[1][0] == '$')
      {
        // 获取上一个命令的退出码
        if(strcmp(gargv[1]+1,"?") == 0)
        {
          printf("%d\n",lastcode);
        }
        else if(strcmp(gargv[1]+1,"PATH") == 0)
        {
          printf("%s\n",getenv("PATH"));
        }
        lastcode = 0;
        
      }
      return 1;
  
    }
  }
  return 0;
}
int ExecuteCommand()
{
  pid_t id = fork();

  if(id < 0)
  {
    perror("fork");
    return -1;
  }
  else if(id == 0)
  {
    int fd = -1;
    if(redir_type == NoneRedir)
    {

    }
    else if(redir_type == OutputRedir)
    {
      fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
      dup2(fd,1);
    }
    else if(redir_type == AppRedir)
    {
      fd = open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);
      dup2(fd,1);
    }
    else if(redir_type == InputRedir)
    {
      fd = open(filename,O_RDONLY);
      dup2(fd,0);
    }
    else{

    }
    execvpe(gargv[0],gargv,genv);
    exit(1);
  }
  else{
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid > 0)
    {
      lastcode = WEXITSTATUS(status);
    }
  }
  return 0;
}

int main()
{
  // 0.配置文件填充环境变量表
  LoadEnv();

  char command_line[MAXSIZE] = {0};
  while(1)
  {
    // 1.打印命令行
    PrintCommandLine();
    // 2.获取输入
   if(!GetCommand(command_line,sizeof(command_line)))
   {
     continue;
   }
   //printf("%s\n",command_line);
   // 3.解析命令行 "ls -a -l" --> "ls" "-a" "-l"
   ParseCommand(command_line);
  
   // 解析重定向
   ParseRedir(command_line);


   // 4.内建命令
   if(CheckBuiltinExecute())
   {
     continue;
   }
   // 5.让子进程执行命令
   ExecuteCommand();
  
  }


  return 0;
}
